home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Tools / Languages / MacHaskell 2.2 / progs / prelude / PreludeDerivings.hs < prev    next >
Encoding:
Text File  |  1994-09-27  |  8.1 KB  |  215 lines  |  [TEXT/YHS2]

  1. {-
  2.  
  3. This module contains the implementation of derived instances using dynamic
  4. typing and the deriving declaration.  The deriving declaration provides a
  5. template to the compiler which is expanded syntacticly for each deriving in a
  6. data declaration.  Dynamic typing allows a single routine to be used for
  7. all data declarations.
  8.  
  9. The deriving declaration has the syntax:
  10.  
  11. deriving [<preconditions> =>] <di> <tyvar> where
  12.   {instance [<instance-context> =>] <class> <tyvar1>
  13.      <decls1>}+
  14.  
  15. The preconditions are class constraints on the data type to be derived.
  16. The declaration:
  17.   deriving Text t => Foo t where
  18. would require the Text instance of a type t be available in order to derive
  19. Foo.  A compile time error occurs when Text t is not satisfied.  Two special
  20. psuedo-classes can be used: EnumType and EnumOrTupleType.  Only enumerated types
  21. satify EnumType and only enumerated or tuple types satisfy EnumOrTupleType.
  22.  
  23. The <di> is the name of the derived instance.  These names are used only
  24. following "deriving" in data declarations.  This file defines the Text, Binary,
  25. Eq, Ord, Ix, and Enum instances defined by the report.  Currently there is
  26. no way to name derived instances in import/export lists - sorry! - but they
  27. are exported by default when no export list is provided.
  28.  
  29. The <tyvar> is used in both the preconditions and the instance declarations
  30. to denote the data type being derived from.
  31.  
  32. Each instance declaration is a standard Haskell instance declaration except
  33. for the context.  Instead of a data type, the <tyvar> appears in its place
  34. in the instance declaration.  The context cannot refer to components of the
  35. type directly as in an ordinary instance declaration since the type is not
  36. yet known.  Instead, this context refers to the structure components of the
  37. type instantiated by a deriving.  Thus
  38.  
  39. deriving Text t where
  40.   instance Text t => Text t where
  41.     ...
  42.  
  43. indicates that to derive Text for a type T, all types which appear as arguments
  44. to a constructor for T must also be in Text.  This is the condition 
  45. found in all of the instances presently in the Haskell standard.
  46.  
  47. A deriving may create more than one instance declaration and the name
  48. of the derived instances need not match the class created.  For example,
  49.  
  50. deriving NewText t where
  51.   instance Text t => Text t where
  52.     ... some alternative way to define text ...
  53.  
  54. would be allowed.  Of course, using NewText would preclude the use of the
  55. usual Text instance.
  56.  
  57.  
  58.  
  59. Notes:
  60.  
  61. Users are free to add new derived instances using the deriving declaration.
  62. This is usually done in conjunction with dynamic typing.
  63.  
  64. Identifiers in the instance declarations are scoped within the module containing
  65. the deriving declaration.
  66.  
  67. Dynamic types are not all that fast - until partial evaluation can be used
  68. to speed things up this will not have the performance of the purely syntactic
  69. expansions conventionally used for derived instances.  However, since the
  70. syntactic expansions for the six standard derivable instances were already
  71. present in our compiler, we use these instead of dynamic typing for all
  72. instances except Text.  The Text instance can cause major program bloat
  73. for large data types and the dynamic version, although slower, generates 
  74. very little code for each type.  Someday we might allow the syntactic
  75. expansion of Text instances to be selected by the user for greater speed
  76. but presently this is not possible.
  77.  
  78. The code in the instance templates cannot contain some Haskell constructs.
  79. This is due to laziness on my part and could be fixed.  However, this code
  80. usually calls into dynamic handlers with almost no computation so this should
  81. not be a problem.
  82.  
  83. Limitations of the dynamic typing system result in some rather convoluted
  84. code for the 'readsPrec' instance.  This could be cleaned up with some
  85. additional dynamic typing constructs.
  86.  
  87. Efficiency could be dramaticly increased using 'unsafe' dynamic typing
  88. constructs.  Presently, every dynamic operation is type checked at runtime
  89. even though the check will never fail in the dynamic handler found here.
  90.  
  91. One non-obvious aspect of this is the relation between the instance
  92. declaration context in the deriving declaration and the types captured
  93. by toDynamic.  The calls to toDynamic see the context supplied by the
  94. instance declaration and package this context in the dynamics created.
  95. If these contexts are omitted, runtime type type checks will fail.
  96.  
  97. Tuples use a slightly different approach to this problem (much less elegent!)
  98. and these handlers are not used by tuples.  PreludeTuple has these.
  99.  
  100. -}
  101.  
  102. -- This module exports the six instances derived via the Haskell report.
  103. module PreludeDerivings where
  104.  
  105. {-# Prelude #-}
  106.  
  107. import Dynamic
  108. import PreludeDynamicHandlers
  109.  
  110. -- This is used to implement derived instances
  111.  
  112. deriving Text t where
  113.   instance Text t => Text t where
  114.     showsPrec p x = showDynamic p (toDynamic x)
  115.     readsPrec p s = t where
  116.       [(obj,_)] = t
  117.       t = map (\(v,s) -> (fromDynamic v,s)) (readDynamic (typeOf obj) p s)
  118.  
  119. -- Note!!! For the Binary, Eq, Ord, Ix, and Enum classes dynamic typing is
  120. -- not used and the compiler generates the instance functions directly.
  121. -- This is because these instance functions are usually fairly short and
  122. -- much more efficient (and because we already had this code written!).
  123. -- The Text functions could be done this way but are not at the moment.
  124. -- The declarations in the instance for these classes is ignored!
  125.  
  126. deriving Binary t where
  127.   instance Binary t => Binary t
  128.      -- Generated internally
  129.     
  130. deriving Eq t where
  131.   instance Eq t => Eq t
  132.      -- Generated internally
  133.  
  134. deriving Eq t => Ord t where
  135.   instance Ord t => Ord t
  136.      -- Generated internally
  137.  
  138. deriving (Ord t,EnumOrTupleType t) => Ix t where
  139.   instance Ix t => Ix t
  140.      -- Generated internally
  141.  
  142. deriving (Ord t,EnumType t) => Enum t where
  143.   instance Enum t
  144.      -- Generated internally
  145.  
  146.  
  147. module PreludeDynamicHandlers where
  148.  
  149. import DynamicInternal
  150.  
  151.  
  152. {-# Prelude #-}
  153.  
  154.  
  155. showDynamic d x | dConstructorInfix c = showInfix (dConstructorFixity c)
  156.                 | otherwise = showPrefix where
  157.   c = dConstructor x
  158.   slots = dSlots x
  159.   showSlot d (val :: Text a => a) = showsPrec d val
  160.   showName = showString (dConstructorName c)
  161.  
  162.   showInfix f = showParen (d > p) 
  163.                   (showSlot lp s1 . showChar ' ' . showName .
  164.                                     showChar ' ' . showSlot rp s2) where
  165.      [s1,s2] = slots
  166.      (p,lp,rp) = getFixities f
  167.  
  168.   showPrefix | null slots = showName
  169.              | otherwise = showParen (d >= 10) (showName . showSlots slots)
  170.   showSlots [] = id
  171.   showSlots (x:xs) = showChar ' ' . showSlot 10 x . showSlots xs
  172.  
  173.  
  174. getFixities :: Fixity -> (Int,Int,Int)
  175. getFixities f = case f of
  176.   NoFixity -> (9,9,10)
  177.   InfixL p -> (p,p,p+1)
  178.   InfixR p -> (p,p+1,p)
  179.   InfixN p -> (p,p+1,p+1)
  180.  
  181. readDynamic ty d s = concat (map readCon (dDataTypeConstrs t)) where
  182.   MkSignature _ (Tycon t _) = ty
  183.   readCon c | dConstructorInfix c = readInfix c s
  184.             | otherwise = readPrefix c s
  185.   readPrefix c = readParen ((d > 9) && (dConstructorArity c /= 0)) readVal where
  186.       readVal r = [(dBuild c args,s2) |
  187.                      (token,s1) <- lex r,
  188.                      token == dConstructorName c,
  189.                      (args,s2) <- readArgs s1 (dSlotTypes c ty) ]
  190.       readArgs s [] = [([],s)]
  191.       readArgs s (t:ts) = [ (a:args,s3) | (a,s4) <- readSingle s t 10,
  192.                                           (args,s3) <- readArgs s4 ts]
  193.  
  194.   readInfix c = readParen (d > p) readVal where
  195.       (p,lp,rp) = getFixities (dConstructorFixity c)
  196.       readVal r = [(dBuild c [u,v],s2) |
  197.                      (u,s0)   <- readSingle r ty1 lp ,
  198.                      (tok,s1) <- lex s0, tok == dConstructorName c,
  199.                      (v,s2)   <- readSingle s1 ty2 rp]
  200.       [ty1,ty2] = dSlotTypes c ty      
  201.  
  202. -- This is convoluted!!  
  203. readSingle s t p = res (MkDynamic t (error "Foo")) where
  204.    res (z :: a) = map (\(val,str) -> 
  205.                           (toDynamic (asTypeOf val z),str :: String))
  206.                     (fromDynamic r)
  207.    r = dCoerce (toDynamic (readsPrec p s)) (readResultType t)
  208.    readResultType t = dApplyType (typeOf (error "foo" :: a -> [(a,String)])) [t]
  209.  
  210. readResultType t = dApplyType (typeOf (error "foo" :: a -> [(a,String)])) [t]
  211.  
  212.  
  213. -- The following printers are used by the debugger and error reporting routines.
  214.  
  215.